package com.ctsi.framework.common.exception;

import com.ctsi.commons.util.UtilValidate;
import com.ctsi.framework.common.constant.ResponseCodeEnum;
import com.ctsi.framework.common.response.UnifiedResponse;
import com.ctsi.framework.common.response.UnifyResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.xml.bind.ValidationException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 统一异常处理
 *
 * @author zhangjw
 *  200 响应结果正常；
 *  * 400 错误的请求，如用户提交了非法的数据；
 *  * 401 未授权的请求。
 *  * 403 禁止请求；
 *  * 404 请求的内容不存在；
 *  * 500 服务器内部错误，通常是未预期到的、不可恢复的服务端异常。
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(BaseException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @Deprecated
    public UnifyResponse<String> baseExceptionHandler(HttpServletResponse response, BaseException ex) {
        logger.error(ex.getMessage(),ex);
        return UnifyResponse.error(ex.getCode(),ex.getMessage());
    }

    @ExceptionHandler(TypeMismatchException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @Deprecated
    public UnifyResponse<String> argumentsExceptionHandler(HttpServletResponse response, TypeMismatchException ex) {
        logger.error(ex.getMessage(),ex);
        return UnifyResponse.error(ResponseCodeEnum.GL99990100);
    }
// ---------------------------------------------------------------------------------------------------------------------------------------------------
    @Autowired
    private ExceptionFactory exceptionFactory;
    @Autowired
    private MessageSource messageSource;

    /**
     * 给开发人员对接接口使用，不会面向用户
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public UnifiedResponse handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        logger.error("缺少请求参数", e);
        return UnifiedResponse.error(CoreErrorConstant.COMMON_ARGS_ILLEGAL_ERROR,e.getMessage());
    }

//    @ResponseStatus(HttpStatus.BAD_REQUEST)
//    @ExceptionHandler(IllegalArgumentsException.class)
//    @ResponseBody
//    public UnifiedResponse handleIllegal(IllegalArgumentsException e) {
//        logger.error("非法参数异常", e);
//        if (UtilValidate.isNotEmpty(e.getAddition())) {
//            return UnifiedResponse.error(e.getRet(),e.getMessage(),e.getAddition());
//        }
//        return UnifiedResponse.error(e.getRet(),e.getMessage());
//    }

    /**
     * 方法参数校验异常处理,会面向客户
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public UnifiedResponse beanValidation(MethodArgumentNotValidException e){
        List<Map<String,String>> errors = e.getBindingResult().getFieldErrors().stream()
                .map(fieldError -> {
                    Map<String,String> result = new HashMap<>();
                    result.put(fieldError.getObjectName(),messageSource.getMessage(fieldError.getDefaultMessage(),null, Locale.CHINA));
                    return result;
                }).collect(Collectors.toList());

        logger.error("非法参数异常:{}",errors);

        return UnifiedResponse.error(CoreErrorConstant.COMMON_ARGS_ILLEGAL_ERROR,errors);
    }

    /**
     * 会面向客户
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({BindException.class})
    public UnifiedResponse beanValidation(BindException e){
         List<Map<String,String>> errors = e.getBindingResult().getFieldErrors().stream()
                .map(fieldError -> {
                    Map<String,String> result = new HashMap<>();
                    result.put(fieldError.getObjectName(),messageSource.getMessage(fieldError.getDefaultMessage(),null, Locale.CHINA));
                    return result;
                }).collect(Collectors.toList());

         logger.error("非法参数异常:{}",errors);

         return UnifiedResponse.error(CoreErrorConstant.COMMON_ARGS_ILLEGAL_ERROR,errors);
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public UnifiedResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        logger.error("参数解析失败", e);
        return UnifiedResponse.error(CoreErrorConstant.COMMON_ARGS_ILLEGAL_ERROR,e.getMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(ConstraintViolationException.class)
    public UnifiedResponse handleServiceException(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        ConstraintViolation<?> violation = violations.iterator().next();
        String message = violation.getMessage();
        logger.error("参数验证失败 {},{}", e,message);
        return UnifiedResponse.error(CoreErrorConstant.COMMON_ARGS_ILLEGAL_ERROR,e.getMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(ValidationException.class)
    public UnifiedResponse handleValidationException(ValidationException e) {
        logger.error("参数验证失败", e);
        return UnifiedResponse.error(CoreErrorConstant.COMMON_ARGS_ILLEGAL_ERROR,e.getMessage());
    }

    /**
     * 不会面向客户，只面向开发人员
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public UnifiedResponse noHandlerFoundException(NoHandlerFoundException e) {
        logger.error("Not Found", e);
        return UnifiedResponse.error(CoreErrorConstant.COMMON_HTTPMETHOD_NOT_FOUNT,e.getMessage());
    }

    /**
     * 不会面向客户，只面向开发人员
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public UnifiedResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        logger.error("不支持当前请求方法", e);
        return UnifiedResponse.error(CoreErrorConstant.COMMON_HTTPMETHOD_NOT_SUPPROT,e.getMessage());
    }

    /**
     * 不会面向客户，只是面向开发人员
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public UnifiedResponse handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        logger.error("不支持当前媒体类型", e);
        return UnifiedResponse.error(CoreErrorConstant.COMMON_HTTP_MEDIATYPE_NOT_SUPPORT,e.getMessage());
    }


    /**
     * 自定义oauth2 授权异常处理
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(AuthErrorException.class)
    @ResponseBody
    public UnifiedResponse handleAuthError(AuthErrorException e) {
        logger.error("授权验证异常", e);
        if (UtilValidate.isNotEmpty(e.getAddition())) {
            return UnifiedResponse.error(e.getRet(),e.getMessage(),e.getAddition());
        }
        return UnifiedResponse.error(e.getRet(), e.getMessage());
    }

    /**
     *
     * @param e
     * @return
     */
    @ResponseStatus(value = HttpStatus.FORBIDDEN)
    @ExceptionHandler(ForbiddenException.class)
    @ResponseBody
    public UnifiedResponse handleForbidden(ForbiddenException e) {
        logger.error("禁止异常", e);
        if (UtilValidate.isNotEmpty(e.getAddition())) {
            return UnifiedResponse.error(e.getRet(),e.getMessage(),e.getAddition());
        }
        return UnifiedResponse.error(e.getRet(), e.getMessage());
    }

    /**
     * 自定义资源不存在异常
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseBody
    public UnifiedResponse handleNotFound(ResourceNotFoundException e) {
        logger.error("对象没找到异常", e);
        if (UtilValidate.isNotEmpty(e.getAddition())) {
            return UnifiedResponse.error(e.getRet(),e.getMessage(),e.getAddition());
        }
        return UnifiedResponse.error(e.getRet(), e.getMessage());
    }

    /**
     * 自定义冲突异常处理
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.CONFLICT)
    @ExceptionHandler(ConflictException.class)
    @ResponseBody
    public UnifiedResponse handleConflict(ConflictException e) {
        logger.error("冲突异常", e);
        if (UtilValidate.isNotEmpty(e.getAddition())) {
            return UnifiedResponse.error(e.getRet(),e.getMessage(),e.getAddition());
        }
        return UnifiedResponse.error(e.getRet(), e.getMessage());
    }

    /**
     * 自定义异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(BasedException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public UnifiedResponse handleResponse(BasedException e) {
        logger.error("全局捕获自定义异常", e);
        if (UtilValidate.isNotEmpty(e.getAddition())) {
            return UnifiedResponse.error(e.getRet(),e.getMessage(),e.getAddition());
        }
        return UnifiedResponse.error(e.getRet(), e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public UnifiedResponse<Void> handleOtherException(Exception e) {
        logger.error("全局捕获未知异常", e);
        return exceptionFactory.createInternalError();
    }

}
